package fr.red5.net
{
	/**
	 * Copyright (C) 2006-2007 
	 * Younes BENAOMAR <younes@virtual-industry.com>
	 *
	 * This library is free software; you can redistribute it and/or
	 * modify it under the terms of the GNU Lesser General Public
	 * License as published by the Free Software Foundation; either
	 * version 2.1 of the License, or (at your option) any later version.
	 * 
	 * This library is distributed in the hope that it will be useful,
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	 * Lesser General Public License for more details.
	 * 
	 * You should have received a copy of the GNU Lesser General Public
	 * License along with this library; if not, write to the Free Software
	 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
	 *
	 */
	 
	import flash.events.*;
	import flash.net.*;
	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import mx.controls.*;
	
	import fr.red5.events.Red5ErrorEvent;
	import fr.red5.net.so.RemoteSharedObject;
	import fr.red5.events.CallBackEvent;
	import fr.red5.events.ConnectionSuccessEvent;
	
	public class Red5Connection extends Proxy implements IEventDispatcher 
	{

		private var dispatcher:EventDispatcher;
		
		private var _sharedObjects:Dictionary;
		
		protected var isconnected:Boolean;
		protected var loggedIn:Boolean;
		
		protected var myUsername:String;
		protected var myPassword:String;
		protected var myServer:String
				
		private var nc:NetConnection;
		
		
		public function Red5Connection(){
			dispatcher = new EventDispatcher(this);
			_sharedObjects = new Dictionary();
			initialize();
		}
				
		private function initialize():void{
			nc = new NetConnection();
			nc.client = this;
			nc.objectEncoding = flash.net.ObjectEncoding.AMF0;
			nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
			nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
			nc.addEventListener(IOErrorEvent.IO_ERROR, inputOutputErrorHandler); 
			
		}
		
		public function connect():Boolean{
			isconnected = false;
			loggedIn = false; 
			if(server == null)
			{
				throw new Error("please provide a valid URI connection string", "URI Connection String missing");
				return false;
			}else if(connected)
			{
				throw new Error("You are already connected to " + server, "Already connected");
				return false;
			}								
			nc.connect(server,username,password);
			return true;
		}
		
		public function disconnect():void{
			if(connected){
				nc.close();
			}
		}
		
		
		private function netStatusHandler(event:NetStatusEvent):void 
		{
			switch(event.info.code)
			{
				case "NetConnection.Connect.Failed":
					dispatchError( "connection-failed", "Connection to remote server failed", "cancel", 502 );
				break;
				
				case "NetConnection.Connect.Success":
					notifyConnect();
				break;
				
				case "NetConnection.Connect.Rejected":
					dispatchError( "connection-rejected", "Remote server reject connection", "cancel", 503 );
				break;
				
				case "NetConnection.Connect.Closed":
					dispatchError( "connection-closed", "Remote connection closed", "cancel", 504 );
				break;
				
				case "NetConnection.Connect.InvalidApp":
					dispatchError( "connection-failed", "Remote application doesn't exist", "cancel", 505 );
				break;
				
				case "NetConnection.Connect.AppShutdown":
					dispatchError( "connection-closed", "Remote shutdown application", "cancel", 506 );
				break;
			}
		}
			
		protected function inputOutputErrorHandler(event:IOErrorEvent):void {
			//TODO	
		}
		
		protected function asyncErrorHandler(event:AsyncErrorEvent):void{
			dispatchError( "asyncError", event.text, "cancel", 507 );
		}
		
        protected function securityErrorHandler(event:SecurityErrorEvent):void {
            dispatchError( "security-error", "A security error occurred! Details:"+ event.text, "cancel", 506 );
        }
        	
		protected function dispatchError( condition:String, message:String, type:String, code:Number ):void
		{
			var event:Red5ErrorEvent = new Red5ErrorEvent();
			event.errorCondition = condition;
			event.errorMessage = message;
			event.errorType = type;
			event.errorCode = code;
			dispatchEvent( event );
		}
				

		
		protected function notifyConnect():void
		{
			isconnected = true;
			var event:ConnectionSuccessEvent = new ConnectionSuccessEvent();
			dispatchEvent( event );
		}
		
		/*
		flash_proxy override function callProperty(methodName:*, ...args):* {
			try {
				nc.call(methodName, this, args);
			} catch (error:Error){
				
			}
			return null;
		}
		
		*/
		flash_proxy override function getProperty(name:*):* {
			var handler:Function = function(... args):void{
				var evt:CallBackEvent = new CallBackEvent(name);
				evt.data = args;
				dispatchEvent(evt);
			}
		       return handler;
		}

	    public function callMethod(name:String,responder:Responder, args:Array):void {
			var callArgs:Array = new Array(name,responder);
			nc.call.apply(null,callArgs.concat(args))
		}
		
		
		public function getSharedObject(name:String, persistance:Boolean=false):RemoteSharedObject
		{
			if(_sharedObjects[name] == null){
				var so:RemoteSharedObject = new RemoteSharedObject(name, netConnection, persistance);	
				_sharedObjects[name] = so;
				return so;
			}else{
				return _sharedObjects[name];
			}
		}
		
		/**
		* Checks whether there's a SO with given name
		* @param	SO name
		* @return	true if SO existe
		*/
		public function hasSharedObject(name:String):Boolean{
			return _sharedObjects[name];
		}
		
		public function get netConnection():NetConnection
		{
			return nc;
		}
								
		/**
		 * The Red5 server to use for connection.
		 *
		 * @availability Flash Player 9
		 */
		public function get server():String
		{
			return myServer;
		}
		
		public function set server( theServer:String ):void
		{
			myServer = theServer;
		}
			
		/**
		 * The username to use for connection.
		 *
		 * @availability Flash Player 9
		 */
		public function get username():String
		{
			return myUsername;
		}
		
		public function set username( theUsername:String ):void
		{
			myUsername = theUsername;
		}
				
		/**
		 * The password to use when logging in.
		 *
		 * @availability Flash Player 9
		 */
		public function get password():String
		{
			return myPassword;
		}
		
		public function set password( thePassword:String ):void
		{
			myPassword = thePassword;
		}		
		
		public function get connected():Boolean{
			return isconnected;
		}
	
		public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void{
			dispatcher.addEventListener(type, listener, useCapture, priority);
		}
	       
		public function dispatchEvent(evt:Event):Boolean{
			return dispatcher.dispatchEvent(evt);
		}
	
		public function hasEventListener(type:String):Boolean{
			return dispatcher.hasEventListener(type);
		}
	
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void{
			dispatcher.removeEventListener(type, listener, useCapture);
		}
	          
	               
		public function willTrigger(type:String):Boolean {
			return dispatcher.willTrigger(type);
		}

	}
}